[TOC]

小程序教程

🔰第1阶段

🕒开发工具下载和安装

小程序开发工具下载地址:

https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html

🕒创建项目

  1. 可以新建,也可以导入原有项目
  2. 需要去注册一个小程序以获得AppId, 当然也可以使用测试号

🕒新建页面

(1) 新增页面

打开app.json文件, 在里面新增一个"我的"的页面, 注意格式:

  • 在"pages"里添加 "pages/my/my",
  • 需要使用双引号包起来, 后面加逗号
  • 最后一条不用加逗号, 加了会报错
  • 按ctrl+s 进行保存(也可以在菜单栏的文件里设置自动保存)
{
  "pages":[
    "pages/index/index",
    "pages/my/my",
    "pages/logs/logs"
  ],
  "window":{
    "backgroundTextStyle":"light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "Weixin",
    "navigationBarTextStyle":"black"
  },
  "style": "v2",
  "sitemapLocation": "sitemap.json"
}

(2) 每个页面的4个相关文件

在右边的pages文件夹里, 会多出一个my文件夹, 里面有几个文件:

  • my.wxml 用来编写页面内容的
  • my.wxss 用来写样式装饰内容的
  • my.js 用来给页面添加行为的
  • my.json用来配置页面的, 比如导航栏的标题

(3) 查看页面

  • 点击菜单栏的编译模式, 点击添加编译模式
  • pages/index/index 改成 pages/my/my, 点击确定
  • 刷新页面即可

(4) 配置页面

  • 修改导航栏标题, 在my.json里添加 "navigationBarTitleText": "个人中心"

  • 修改背景颜色, 在my.json里添加 "navigationBarBackgroundColor": "#c03d37"

    {
      "usingComponents": {},
      "navigationBarTitleText": "个人中心",
      "navigationBarBackgroundColor": "#c03d37"
    }
    

🕒小程序组件

  • view 容器组件(块级组件)
  • text 文本组件(行内组件)
  • 按钮和图标
  • 表单组件
    • 输入框
    • 单选框
    • 多选框
    • 下拉列表等
  • 音频和视频
    • audio 音频
    • video 视频
  • 图片组件 image
  • 链接组件 navigator

🕒给组件添加样式

(1) 全局样式

在app.wxss里设置的样式是全局样式, 所有页面只要匹配得上都会有效果

(2) 页面根容器(根标签)的样式

比如在my.wxss里, 写以下代码

page {
  background: gray; /*把页面背景设置为灰色*/
}

(3) 对某个组件(标签)设置样式

view{
	border: 1px solid red;   /*给所有的view组件添加边框*/
}

wxml代码

<view class="red">
view组件1
</view>
<view class="red">
view组件2
</view>

(4) 给某一类的组件(标签)添加样式

.red {
  /* 给所有含有class="red"的组件的字体颜色变成红色 */
  color: red;
}

wxml代码

<view class="red">
这是个view组件
</view>

<text class="red">
这是个text组件
</text>

🕒配置小程序底部tab栏

(1) 准备工作

  1. 新建4个页面: film(电影), cinema(影院), video(视频), my(我的)
  2. 每个页面随便写点什么内容
  3. 准备4个tab栏对应的图片, 每个tab栏2张图片

(2) app.json 配置文件详解

{
  // 页面路径(地址)
  "pages": [
    "pages/film/film",
    "pages/cinema/cinema",
    "pages/video/video",
    "pages/my/my"
  ],
  "window": { 
    // 下拉 loading 的样式不用管
    "backgroundTextStyle": "dark",
    // 导航栏背景颜色
    "navigationBarBackgroundColor": "#c03d37",
    // 导航栏文字
    "navigationBarTitleText": "百色电影",
    // 导航栏文字颜色
    "navigationBarTextStyle": "white"
  },
  "style": "v2",
  "sitemapLocation": "sitemap.json",
  "tabBar": {
    // tab栏字体默认颜色
    "color": "#000000",
    // tab栏被选中时的字体颜色
    "selectedColor": "#c03d37",
    "list": [{
       // 页面路径(地址)
        "pagePath": "pages/film/film",
        // tab栏文字
        "text": "首页",
        // tab栏默认图片
        "iconPath": "./img/film.png",
         // tab栏被选中时的图片
        "selectedIconPath": "./img/filming.png"
      },
      {
        "pagePath": "pages/cinema/cinema",
        "text": "影院",
        "iconPath": "./img/cinema.png",
        "selectedIconPath": "./img/cinemaing.png"
      },
      {
        "pagePath": "pages/video/video",
        "text": "视频",
        "iconPath": "./img/video.png",
        "selectedIconPath": "./img/videoing.png"
      },
      {
        "pagePath": "pages/my/my",
        "text": "我的",
        "iconPath": "./img/my.png",
        "selectedIconPath": "./img/mying.png"
      }
    ]
  }
}

🕒编写静态页面

必备知识: 弹性盒子

  • display: flex 把一个元素设置为弹性盒子
  • align-items 垂直对齐方式
    • flex-start 顶部对齐
    • center 垂直居中
    • flex-start 底部对齐
  • justify-content 水平对齐方式
    • flex-start 左对齐
    • center 水平居中
    • flex-end 右对齐
    • space-around 分散对齐
    • space-between 两端对齐
  • flex-grow 剩余空间分配
    • 对子元素(组件)进行设置
    • 子元素都设置为1, 表示把剩余空间平均分配, 每个子元素获得1份
    • 对某个子元素设置为1, 表示把剩余空间分成1分, 全给了该子元素(常用)

首页代码

film.wxml

<!-- 轮播图 -->
<image class="swiper" src="https://static.maizuo.com/v5/upload/6f5e10201aaea65b311d7ab562ba097c.jpg?x-oss-process=image/quality,Q_70"></image>

<!-- tab栏 -->
<view class="tabs">
  <text class="tab active">热映</text>
  <text class="tab">待映</text>
  <text class="tab">经典</text>
</view>

<!-- 电影列表 -->
<view class="list">
<!-- 每一部电影 -->
  <view class="item">
    <image class="img" src="https://pic.maizuo.com/usr/movie/6d31257bd0c897f0a953b7097853d627.jpg"></image>
    <view class="text">
      <view>我和我的父辈</view>
      <view> 观众评分 <text class="yellow">7</text></view>
      <view>主演:吴京|章子怡|徐峥|沈腾</view>
      <view>中国大陆 | 100分钟</view>
    </view>
    <view class="buy">购票</view>
  </view>
  <view class="item">
    <image class="img" src="https://pic.maizuo.com/usr/movie/6d31257bd0c897f0a953b7097853d627.jpg"></image>
    <view class="text">
      <view>我和我的父辈</view>
      <view> 观众评分 <text class="yellow">7</text></view>
      <view>主演:吴京|章子怡|徐峥|沈腾</view>
      <view>中国大陆 | 100分钟</view>
    </view>
    <view class="buy">购票</view>
  </view>
  <view class="item">
    <image class="img" src="https://pic.maizuo.com/usr/movie/6d31257bd0c897f0a953b7097853d627.jpg"></image>
    <view class="text">
      <view>我和我的父辈</view>
      <view> 观众评分 <text class="yellow">7</text></view>
      <view>主演:吴京|章子怡|徐峥|沈腾</view>
      <view>中国大陆 | 100分钟</view>
    </view>
    <view class="buy">购票</view>
  </view>
</view>

film.wxss 代码

page {
  /* 整个页面的背景颜色 */
  background-color: #f4f4f4;
}
.swiper {
  width: 100%;
}

.tabs {
  background-color: #fff;
  /* 设置辅助边框 */
  /* border: 1px solid red; */
  /* 高度44px, 88rpx, 用rpx可以自动适配 */
  height: 88rpx;
  display: flex;
  /* 垂直居中 */
  align-items: center;
  justify-content: space-around;
}

.tab {
  /* border: 1px solid green; */
  height: 100%;
  display: flex;
  align-items: center; 
}
.active {
  border-bottom: 2px solid #c03d37;
}

/* 电影列表 */
.list {
  margin-top: 20rpx;
  /* border: 1px solid red; */
}
.item {
  padding-left: 30rpx;
  padding-right: 30rpx; 
  height: 218rpx;
  display: flex;
  align-items: center;
  justify-content: space-between;
  background-color: #fff;
}
.item image {
  width: 132rpx;
  height: 200rpx;
}
.item .text {
  margin-left: 20rpx;
  flex-grow: 1;
}
.item .buy {
    border: 2rpx solid #c03d37;
    padding: 10rpx 20rpx;
    color: #c03d37;
}
.item .yellow {
  color:#ffb232;
}

🔰第2阶段

最好新建一个demo页面, 专门用来研究新知识

🕒 绑定点击事件

(1) 一个简单的例子

demo.wxml

<button type="primary" bindtap="test">按钮</button>

demo.js

Page({
  test(event) {
    console.log(22222);
    console.log(event); // 事件对象
  },
})

(2) 调试器和控制台

  • 上面代码 console.log(22222);意思是在控制台打印22222
  • 控制台打开步骤: 左上角调试器=> 右下角Console=> 右下角侧边栏info展示的就是打印的信息
  • errors 展示的错误信息
  • warnings 展示的是警告信息

🕒 渲染页面

(1) data和setData

data数据的存放的地方

需要在页面展示的数据放在data:{}里, 如下:

data里存放了两个数据, 一个是title, 它的值是'小程序实训', 另一个是user, 存放了一个用户的信息, 这里data可以理解成一个大容器, 而title和user都是一个小容器, 用来存放数据

Page({
  data: {
    title: '小程序实训',
    user: {
      name: '张三',
      age: 18
    }
  } 
})

展示数据

data里的数据可以放在wxml里进行展示

<view>
  标题: {{title}}
</view>

<view>
  <text>
    姓名: {{user.name}}
  </text>
  <text>
    年龄: {{user.age}}
  </text>
</view>

setData修改数据

demo.wxml

<view>
  标题: {{title}} 
</view>


<view>
  <text>
    姓名: {{user.name}}
  </text>
  <text>
    年龄: {{user.age}}
  </text>
</view>  
<button type="primary" bindtap="change">修改</button>

demo.js

// pages/demo/demo.js
Page({
  data: {
    title: '小程序实训',
    user: {
      name: '张三',
      age: 18
    }
  },
  
  change() {
    this.setData({
      title: 'web前端实训',
      user: {
        name: '李四',
        age: 20
      }
    })
  }
})

(2) 列表展示(列表渲染)

简单列表展示

demo.wxml

<view>狂飙演员列表</view>
<view wx:for="{{list}}">
  <text>{{index+1}}.</text>
  <text>{{item}}</text>
</view>

demo.js

Page({
  data: {
    list: ['张译', '张颂文', '李一桐', '张志坚', '吴刚', '倪大红', '程隆妮', '高叶']
  }, 
})

复杂数据列表

demo.js

Page({
  data: {
      list: [{
              name: '张译',
              age: 18,
              address: '广西'
          },
          {
              name: '张颂文',
              age: 19,
              address: '广西'
          },
          {
              name: '李一桐',
              age: 20,
              address: '广东'
          },
          {
              name: '张志坚',
              age: 18,
              address: '广东'
          },
          {
              name: '吴刚',
              age: 17,
              address: '广南'
          },
          {
              name: '倪大红',
              age: 33,
              address: '广南'
          },
          {
              name: '程隆妮',
              age: 22,
              address: '广北'
          },
          {
              name: '高叶',
              age: 20,
              address: '广北'
          },
      ]
  },
})

demo.wxml

<view>狂飙演员列表</view>
<view wx:for="{{list}}">
  <text>{{index+1}}.</text>
  <text>{{item.name}}</text>
  <text>{{item.age}}</text>
</view>

(3) 条件渲染

根据条件来进行渲染, 就是满足条件就显示, 不满足就不显示

例1. wx:if

demo.js

Page({
  data: {
    isMan: true
  },
})

demo.wxml

<view wx:if="{{isMan}}">臭男人</view>

例2. wx:if和wx:else

demo.wxml

<view wx:if="{{isRain}}">雨天</view>
<view wx:else>晴天</view>
<button type="primary" bindtap="change">切换</button>

demo.js

Page({
  data: {
    isRain:true
  },
  change() {
    this.setData({
      isRain: !this.data.isRain
    })
  }, 
})

🕒 获取数据

文档地址: 文档 => api => 网络 => wx.request

例1. 通过按钮获取数据并打印

demo.wxml

<button type="primary" bindtap="getData">获取数据</button>

demo.js

Page({
  data: {
     
  }, 

  // 获取数据的方法
  getData() {
    wx.request({
      url: 'http://81.71.65.4:3008/film/list',    
      success(res) {
        console.log(res.data)
      }
    })
  }
})

点击按钮时, 会出现以下错误, 原因是小程序只支持https的接口, 并且接口地址需要到小程序控制台去配置允许访问(称为合法域名)

解决办法: 开发时只需要在小程序右上角 详情 => 本地配置 => 勾选不校验合法域名......

例2. 获取数据并渲染

第一步: 在data里添加变量list用来存放电影列表

page({
	list: []
})

第二步: 请求数据, 把获取到的列表数据存放入data里的list容器

可以通过控制台的AppData查看数据存放情况

// demo.js
Page({
  data: {
     list: []
  }, 

  // 获取数据的方法
  getData() { 
    wx.request({
      url: 'http://81.71.65.4:3008/film/list',    
      // 需要用箭头函数的写法
      success: (res)=> {
        this.setData({
          list: res.data.data
        })
      }
    })
  }
})

第三步: 使用前面的列表渲染进行列表展示

demo.wx.ml代码

<button type="primary" bindtap="getData">获取数据</button>
<view wx:for="{{list}}">
  <text>电影名称: {{item.name}}</text>
  <image src="{{item.poster}}"></image>
</view>

🕒 生命周期函数

生命周期函数, 是满足条件就会自动执行的函数, 其中用得最多的是onLoad和onShow

小程序有以下生命周期函数

  1. onLoad 生命周期函数--监听页面加载`
  2. onReady 生命周期函数--监听页面初次渲染完成
  3. onShow 生命周期函数--监听页面显示
  4. onHide 生命周期函数--监听页面隐藏
  5. onUnload 生命周期函数--监听页面卸载
  6. onPullDownRefresh 页面相关事件处理函数--监听用户下拉动作
  7. onReachBottom 页面上拉触底事件的处理函数
  8. onShareAppMessage 用户点击右上角分享

🕒 动态页面

动态页面指的是跟后端有数据交互的页面, 否则就叫静态页面

  1. 在data里设置list变量用来存放要展示的列表
  2. 在onShow或者onLoad生命周期里调用获取数据的方法
  3. 成功获取数据后, 把数据存入data的list
  4. 使用页面渲染(列表和条件渲染)来展示页面

将首页变成动态页面



作业: 把视频页面变成动态页面

🕒 函数传参和接口传参

(1) 函数传参

调用一个函数时, 小括号里可以传入参数, 传入不同的参数, 则结果就不一样

function add(a,b) {
  var sum = a+b;
  console.log(sum);
}
add(10,20); // 打印30
add(20,30); // 打印50

(2) 接口传参

什么是请求参数? 就是请求数据的时候告诉服务器端你要什么样的数据

  • 在文档上演示不同的接口参数, 返回不同的内容

(3) 项目应用

🔰第3阶段

🕒 路由跳转和传参

🔰第4阶段

🕒 小程序授权

🕒 小程序登录

🔰第5阶段

🕒 轮播图

🕒 tab栏切换


(4) 项目详情配置

  1. 基本信息配置
  2. 本地配置

(5) 小程序控制台配置

登录小程序: https://mp.weixin.qq.com/

(1) 版本管理

  • 上传代码获得体验版, 体验版需要添加权限才可以访问
  • 体验版转正式版
  • 腾讯审核通过后就变正式版, 所有人都可以访问

(2) 成员管理

(3) 开发管理

  • 开发者id和密钥
  • 服务器域名配置

(6) 小程序使用npm模块

  1. 勾选使用npm
  2. 初始化package.json npm init
  3. npm i 安装依赖
  4. 构建项目

✔静态页面

  1. 使用小程序组件
    1. view 相当于 div
    2. text 相当于span
    3. img变为image
    4. 地图,音视频,画布等
    5. ......
  2. 使用 rpx 作为单位,这个屏幕的宽度为 750rpx
  3. page{} 该页面的最外层的容器
  4. 页面之间的样式不会相互影响, 因为小程序本质上是多页应用
  5. app.wxss是入口的样式, 在这里可以通过@import去加载其它样式
  6. 底部 tab 配置 文档=>框架=>全局配置=>tabBar
  7. 开放数据 文档=>组件=>开放能力=>open-data (停用了)
  8. 编译模式, 编译模式添加启动参数
// 列表跳详情的时候, 会带上id, 比如 url="/detail/detail?id=xxxx"
// 如果此时切换到了detail页面的模式, 刷新数据就没有了
// 这个时候可以编辑detail页面的编译模式, 添加启动参数即可解决问题
  1. 在小程序中使用 vant-ui
https://vant-contrib.gitee.io/vant-weapp/#/home   // 文档地址
  1. 小程序中使用 less

  2. 图片的各种模式

    <view>
      <text>不保持纵横比缩放图片,使图片完全适应(默认)</text>
      <image style="width: 150px;height: 150px;border: 1px solid red;padding:5px;" mode="aspectFill" src="../../img/pic.jpg"></image>
    </view>
    <view>
      <text>保持纵横比缩放图片,使图片的长边能完全显示出来</text>
      <image style="width: 150px;height: 150px;border: 1px solid red;padding:5px;" mode="aspectFit" src="../../img/pic.jpg"></image>
    </view> 
    <view>
      <view>不缩放图片,只显示图片的中间区域</view>
      <image style="width: 250px;height: 250px;border: 1px solid red;padding:5px;" mode="center" src="../../img/pic.jpg"></image>
    </view> 
    <view>
      <view>不缩放图片,只显示图片的左边区域</view>
      <image style="width: 250px;height: 250px;border: 1px solid red;padding:5px;" mode="left" src="../../img/pic.jpg"></image>
    </view> 
    <view>
      <view>缩放模式,宽度不变,高度自动变化,保持原图宽高比不变</view>
      <image style="width: 250px;border: 1px solid red;padding:5px;" mode="widthFix" src="../../img/pic.jpg"></image>
    </view> 
    <view>
      <view>缩放模式,高度不变,宽度自动变化,保持原图宽高比不变</view>
      <image style="width: 150px;height: 250px;border: 1px solid red;padding:5px;" mode="heightFix" src="../../img/pic.jpg"></image>
    </view> 
    

✔小程序生命周期

小程序有以下生命周期

  1. onLoad 生命周期函数--监听页面加载
  2. onReady 生命周期函数--监听页面初次渲染完成
  3. onShow 生命周期函数--监听页面显示
  4. onHide 生命周期函数--监听页面隐藏
  5. onUnload 生命周期函数--监听页面卸载
  6. onPullDownRefresh 页面相关事件处理函数--监听用户下拉动作
  7. onReachBottom 页面上拉触底事件的处理函数
  8. onShareAppMessage 用户点击右上角分享

注意:

  1. onLoad 只会在小程序中执行一次,比如当前页面是 a 页面,我们在 onLoad 发送请求去获取数据,然后我们切到 b 页面,再切回 a 页面的时候,onLoad 不会再触发,也就是不会再重新发请求获取数据
  2. onShow 跟 onLoad 不同,每次切回 a 页面的时候都会触发这个生命周期函数
  3. 所以到底是在 onLoad 发请求还是在 onShow 发请求,要根据实际的业务去做

✔ajax请求获取数据

前言

  1. 小程序只支持 https
  2. 需要到小程序后台配置域名白名单
  3. 项目中请求了非 https 和不在域名白名单上的接口会报错
  4. 开发时可以取消域名校验,就可以请求任意接口,设置方法 小程序右上角详情 =》本地设置 => 不校验合法域名...

(1) 发送请求

文档地址 文档首页 => api => 网络 => 发起请求

// 示例
wx.request({
  url: "test.php", //仅为示例,并非真实的接口地址
  // 请求参数
  data: {
    x: "",
    y: "",
  },
  method: "get", // 请求类型
  header: {
    "content-type": "application/json", // 默认值
  },
  // 成功的回调, 若要获得this,需要使用箭头函数
  success(res) {
    console.log(res.data);
  },
  // 失败的回调
  fail(error) {
    console.log(error);
  },
  // 不管是成功还是失败都会调用此方法
  complete() {
    console.log("done");
  },
});

(2) 使用 promise 封装请求

1. app/request.js

// 封装微信请求
let env = "prod";
let baseUrl = "";
if (env === "dev") {
  // 本地地址
  baseUrl = "http://localhost:3002";
} else if (env === "prod") {
  baseUrl = "http://81.71.65.4:3002";
}
const request = (url,data={},method="get")=> {
  wx.showLoading({
    title: '努力加载中...',
  })
  let token = wx.getStorageSync("token");
  return new Promise((resolve,reject)=> {
      wx.request({
        url: baseUrl + url,
        method,
        data,
        header: {
        	"user-token": token,
      	},
        success(res){  
          if (res.data.code == 666) {
            resolve(res.data);
          } else {
            wx.showToast({
              title: '请求失败',
              icon:'error'
            })
            reject(res.data);
          } 
        },
        fail(err) {  
          console.log(err);
          reject(err.errMsg);
        },
        // 不管请求成功还是失败都会调用此函数
        complete() {
          wx.hideLoading(); 
        }
      })
  }); 
}

export default request;

(3) 统一管理请求

api/index.js

// 统一管理请求
import request from './request';
export const flowerList = (data={})=> {
  return request('/flower/list2',data);
}
export const flowerDetail = (data={})=> {
  return request('/flower/detail',data);
}
  1. 挂载到 app,在页面中就不需要重复加载
// app.js
import * as api from './api/index';
App({
  onLaunch() {  
    this.api = api;
  },
  globalData: {
    userInfo: null
  }
})
  1. 在页面中使用
const app = getApp();
Page({ 
  data: { 
  }, 
  onShow: function () {
      app.api.flowerList().then(res=> {
        console.log(res);
      })
  }, 
})

✔渲染页面

  1. data 和 setData

    可以通过控制台的appdata来查看数据

    Page({
      data: {
        msg: 'hello',
        count: 1
      },
      onLoad(options) {
        setTimeout(() => {
          this.setData({
            count: 10,
            msg: '哈哈哈哈哈哈哈'
          });
        }, 2000)
      }, 
    })
    
  2. 插值表达式 , wxml 中所有的变量都使用(除了wx:key)

    • 如果数组成员是字符串或者数字, wx:key="index"或者wx:key="*this"
    • 如果数组成员是对象, 比如[{name:'zs',id:1}],wx:key="id"
  3. 条件渲染 wx:if

  4. 列表渲染 wx:for 默认有 item 和 index

  5. 双重wx:for时需要其中一个指定 item 和 index

✔绑定事件

文档地址 : 小程序框架 /视图层 /事件系统

<button data-username='张三' bindtap="test">点击1</button>
<button data-username='李四' bindtap="test">点击2</button>
Page({
  test: function(event) {
    // 小程序事件不能像vue那样传参,只能通过自定义属性来传参
    let username = event.target.dataset.username;
    console.log(username);
  },
});

注意: wxml和html一样, 不区分大小写, 页面上的大写, 最后变成了小写

  1. 常见事件类型
类型触发条件最低版本
touchstart手指触摸动作开始
touchmove手指触摸后移动
touchcancel手指触摸动作被打断,如来电提醒,弹窗
touchend手指触摸动作结束
tap手指触摸后马上离开
longpress手指触摸后,超过 350ms 再离开,如果指定了事件回调函数并触发了这个事件,tap 事件将不被触发1.5.0
longtap手指触摸后,超过 350ms 再离开(推荐使用 longpress 事件代替)
transitionend会在 WXSS transition 或 wx.createAnimation 动画结束后触发
animationstart会在一个 WXSS animation 动画开始时触发
animationiteration会在一个 WXSS animation 一次迭代结束时触发
animationend会在一个 WXSS animation 动画完成时触发
touchforcechange在支持 3D Touch 的 iPhone 设备,重按时会触发

✔open-data 开放数据

https://developers.weixin.qq.com/miniprogram/dev/component/open-data.html

<view class="avatar">
  <open-data type="userAvatarUrl"></open-data>
</view> 


.avatar{
  width: 100rpx;
  height: 100rpx;
  border-radius: 50%;
  border: 1px solid #fff;
  overflow: hidden;
  margin: 20rpx auto;
}

✔页面跳转

小程序常用两种方式,普通页面跳转和 tab 栏切换(跳转)

(1) 跳转方式一 通过navigator跳转

通过组件 navigator 进行跳转,需要指定跳转类型 open-type

<view class="btn-area">
  // 普通页面跳转
  <navigator
    url="/page/navigate/navigate?title=navigate"
    hover-class="navigator-hover"
    >跳转到新页面</navigator>
  
  // 跳转到tab栏
  <navigator
    url="/page/index/index"
    open-type="switchTab"
    hover-class="other-navigator-hover">切换 Tab</navigator>

  // 重定向
  <navigator
    url="../../redirect/redirect/redirect?title=redirect"
    open-type="redirect"
    hover-class="other-navigator-hover"
    >在当前页打开</navigator
  >
  
  // 跳转到小程序
  <navigator
    target="miniProgram"
    open-type="navigate"
    app-id=""
    path=""
    extra-data=""
    version="release"
    >打开绑定的小程序</navigator
  >
</view>

(2) 跳转方式二 通过 js 进行跳转

// 普通页面跳转
wx.navigateTo({
  url: "/product/product",
});
// tab栏切换
wx.switchTab({
  url: "/index",
});

✔路由传参

(1) 第一种, 参数是基本数据类型

// 列表页
 <navigator wx:for="{{flowerList}}" class="flex item pl-10 bg-fff" url="/pages/detail/detail?id={{item.id}}"></navigator>
   
// 详情页
  onLoad: function (options) {
    console.log(options.flowerId);
  },       

(2) 第二种, 参数是引用数据类型

    
// 参数为对象时,要先将对象转成字符串
  toDetail() {
    let obj = {useranme: 'zs',age:100};
    // 将对象转成json字符串
    let query = JSON.stringify(obj);
    // 传参
    wx.navigateTo({
      url: '/pages/detail/detail?query='+query,
    }) 
  },
    
 // 获取参数
  onLoad: function (options) {
    let obj = JSON.parse(options.query);
    console.log(obj);
  },

注意: wx.swichTab跳转url后不能带参数

✔数据缓存

  1. 异步方法
wx.setStorage({
  key: "key",
  data: "value",
});
wx.getStorage({
  key: "key",
  success(res) {
    console.log(res.data);
  },
});
  1. 同步方法
wx.setStorageSync("key", "value");
// 例子
let token = 'asdfasdfasjdflasdjf;asdf;asdfjsak;ldf';
wx.setStorageSync('token',token);

let token = wx.getStorageSync('token');

✔用户授权

知识点

  1. 用户授权: 录音授权
  2. 检查用户是否已经授权
  3. 获取用户信息的授权操作

用户授权功能列表 除了开放数据以外,小程序的很多功能都需要获得用户授权,才可以进行下一步的操作 用户授权的功能列表

(1) 用户授权之录音授权

<button bindtap="shouquan">授权</button>
<button bindtap="luyin">开始录音</button>
Page({ 
  // 授权  
  shouquan() {
    wx.authorize({
      // 授权类型
      scope: "scope.record", // scope.camera 摄像头
      success() {
        // 用户已经同意小程序使用录音功能,才能调用录音相关接口
        console.log('授权成功');
      },
      fail() {
        console.log('想要使用录音功能, 请先授权');
      }
    });
  },

  // 录音
  luyin(){
    let obj = wx.getRecorderManager();
    obj.start({
      format: 'mp3'
    });
    obj.onStart((aa) => {
      console.log('开始录音');
    })
    setTimeout(() => {
      obj.stop();
      obj.onStop(res => {
        console.log(res);
        console.log('停止录音')
      })
    }, 10000)
  }
})

(2) 获取用户信息的授权(以前需要, 现在可以直接调用获取用户信息)

  1. scope.userInfo获取用户信息的授权无法通过js直接调起授权窗口
  2. 必须绑定点击事件, 用户去点击才能调起授权, 我想应该是腾讯想提醒用户要慎重
  3. 由于小程序api的调整, 这里获取到头像是一个灰色头像, 若需要获取真正的头像, 详情请看链接
// demo.wxml
<button bindtap="handleClick"> 获取用户信息 </button>

// demo.js
handleClick(e) {  
  wx.getUserProfile({
    desc: '用于完善会员资料',  
    success: (res) => {
      console.log(res); 
    }
  })
},

(3) 获取用户的授权信息

获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限

wx.getSetting({
    success (res) {
        console.log(res.authSetting) 
    }
})

✔小程序获取位置

(1) 获取位置信息

  1. 文档资料

    • 小程序文档->api->位置
    • [腾讯地图API](平时的开发也可以使用百度地图,高度地图):
  2. 添加密钥

    使用位置服务需要先添加密钥, [链接地址]

  3. 获取经纬度

wx.getLocation({
  type: 'wgs84',
  success: (res) => {
    const latitude = res.latitude;
    const longitude = res.longitude;
  },
  fail: (err) => {
    this.setData({
      city: '定位失败,请手动选择'
    })
  }
})

(2) 实际应用:

  1. 获取城市名称(需要上一点提供的经纬度)

     wx.request({
       url: `https://apis.map.qq.com/ws/geocoder/v1/?location=${latitude},${longitude}&key=XBZBZ-OBG63-LOD3N-3QR5Q-X6Z2Q-BFBIR`,
       success: (res) => {
         let cityName = res.data.result.address_component.city;
         console.log(cityName)
       }
     })
    
  2. 计算两个坐标之间的距离

    // 方法定义 lat,lng 
    function GetDistance( lat1,  lng1,  lat2,  lng2){
        var radLat1 = lat1*Math.PI / 180.0;
        var radLat2 = lat2*Math.PI / 180.0;
        var a = radLat1 - radLat2;
        var  b = lng1*Math.PI / 180.0 - lng2*Math.PI / 180.0;
        var s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a/2),2) +
        Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2),2)));
        s = s *6378.137 ;// EARTH_RADIUS;
        s = Math.round(s * 10000) / 10000;
        return s;
    }
    // 调用 return的距离单位为km
    GetDistance(10.0,113.0,12.0,114.0)
    

✔微信和小程序支付流程

(1) 简单流程

第一步:调用登录接口,获取到用户的openid等

第二步:Code,价格等发送给后台,后台发送微信生成预支付订单,并且返回预支付订单信息

第三步:小程序拿到预下单订单信息,发起支付,调起支付APP

第四步:后台验证支付结果

(2) 详细流程

商户系统和微信支付系统主要交互:

1、小程序内调用登录接口,获取到用户的openid,api参见公共api【小程序登录API】

2、商户server调用支付统一下单,api参见公共api【统一下单API】

3、商户server调用再次签名,api参见公共api【再次签名】

4、商户server接收支付通知,api参见公共api【支付结果通知API】

5、商户server查询支付结果,api参见公共api【查询订单API】

在第4步里, 小程序端就调起支付页面

wx.requestPayment({
  timeStamp: '',
  nonceStr: '',
  package: '',
  signType: 'MD5',
  paySign: '',
  success (res) { },
  fail (res) { }
})

(3) app的支付流程

跟小程序的支付流程大致相同, 只是参数不一样而已

https://www.jb51.net/article/247344.htm

✔uniapp微信小程序登录

微信小程序登录前后端流程

  1. 前端: 调用wx.login() 获取code
  2. 前端: 发送请求
  3. 后端: 获取openid和session_key
  4. 后端: 根据open和session_key生成token(自定义登录态)
  5. 前端: 获取token(自定义登录态)并存入缓存
  6. 前端: 请求数据, 请求头带上token
  7. 后端: 解析token, 得到openid, 根据openid进行查询数据, 比如购物车(后端)
  8. 前端: 得到后端返回的数据

(1) 获取code

login() {
				uni.login({
					provider: 'weixin', //使用微信登录
					success: function(res) {
						console.log(res.code);
					}
				});
			}

(2) 获取用户信息

获取用户信息必须绑定按钮(不一定按钮, 其它标签也行), 然后通过wx.getUserProfile来获取

如果头像是灰色, 昵称是'微信用户'请看链接, 关于微信小程序授权后,昵称是“微信用户”,头像是灰色的解决方案

<template>
	<view class="text tac fff mt-5" @click="getUserInfo">获取用户信息</view>
</template>

<script>
	export default {
    methods: {
      getUserInfo() {
				wx.getUserProfile({
					desc: '用户完善个人信息',
					success: (res) => {
						console.log(resuserInfo); 
						this.userInfo = res.userInfo;
					},
					fail: (err) => {
						console.log(err); 
					}
				})
			}
    }
  }
</script>

(3) 微信小程序登录

<button bindtap="denglu">登录</button> 
import {userLogin} from '../../api/index';
Page({
  data: {},
  denglu() {
    wx.getUserProfile({
      desc: '用户信息',
      success(res) { 
        let {iv,encryptedData, userInfo} = res; 
        wx.login({
          success(res) { 
            let code = res.code; 
            userLogin({code,iv,encryptedData, userInfo}).then(res=> {
              console.log(res);
              wx.setStorageSync('token', res.data.token);
            })
          }
        }) 
      },
      fail(err) {
        console.log(err);
      }
    });   
  },
})

✔uniapp 地理位置相关

[腾讯地图API](平时的开发也可以使用百度地图,高度地图):

(1) 地图选址

第一步: hbuildx -> menifest.json -> 微信小程序配置 -> 微信小程序权限配置 -> 位置接口打钩, 描述随便填

第二步: menifest.json 选择最后的源码视图, 在"mp-weixin" 里添加

"mp-weixin" : {
        ...其它配置,
		"requiredPrivateInfos": [
			"getLocation",
			"chooseLocation"
		]
    },

第三步: 调用uni.chooseLocation打开地图选址页面

<template>
	<view>
		<button @click="getAdress">获取位置</button>
		<view class="">
			{{company}}
		</view>
		<view class="">
			{{adress}}
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				company: '',
				adress: ''
			}
		},

		methods: {
			getAdress() {
				uni.chooseLocation({
					success: res => {
						this.adress = res.address;
						this.company = res.name;
					},
					fail: (err) => {
						console.log(err);
					}
				});
			}
		}
	}
</script>

(2) 获取城市名称

  1. 申请qq地图密钥

  2. 获取经纬度

    <template>
    	<button @click="getAdress">获取经纬度</button>
    </template>
    
    <script>
    	export default {
    
    		methods: {
    			getAdress() {
    				uni.getLocation({
    					success: function(res) {
    						console.log(res.longitude);
    						console.log(res.latitude);
    					},
    					fail(err) {
    						console.log(err);
    					}
    				});
    			}
    		}
    	}
    </script>
    
  3. 逆地址解析 (根据经纬度获取城市名称)

    <template>
    	<button @click="getAdress">获取城市名称</button>
    </template>
    
    <script>
    	export default { 
    		methods: {
    			getAdress() {
    				// getLocation获取经纬度
    				uni.getLocation({
    					success: function(res) {
    						let longitude = res.longitude;
    						let latitude = res.latitude;
    						let url = `https://apis.map.qq.com/ws/geocoder/v1/?location=${latitude},${longitude}&key=XBZBZ-OBG63-LOD3N-3QR5Q-X6Z2Q-BFBIR`;
    						// 获取城市名称
    						wx.request({
    							url: url,
    							success: (res) => { 
    								 console.log(res);
    							}
    						})
    
    					},
    					fail(err) {
    						console.log(err);
    					}
    				});
    			}
    		}
    	}
    </script>
    

    https://blog.csdn.net/qq_37215621/article/details/126736239